home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / TEX-UTIL / DVI_DVI1 / dvilj / c / tfm < prev   
Text File  |  1996-02-18  |  8KB  |  250 lines

  1. /* tfm.c -- read tfm widths resident font support in dvilj. Originally
  2.    written by kb@cs.umb.edu in early 1994. Public domain. */
  3.  
  4. /* #define KPATHSEA */
  5. #ifdef KPATHSEA
  6. #include <kpathsea/config.h>
  7. #include <kpathsea/c-fopen.h>
  8. #include <kpathsea/lib.h>
  9. #include <kpathsea/tex-file.h>
  10. #else
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. extern char* TFMpath;
  14. #endif
  15.  
  16. #include "config.h" /* for STRSIZE and tfm_info_type, at least */
  17.                     /* and for IO-functions (since RISC OS) */
  18.  
  19. void Fatal();
  20.  
  21.  
  22. #ifdef vms
  23. #include <ssdef.h>
  24. #include <stsdef.h>
  25. #define getenv vms_getenv
  26. #endif
  27.  
  28. /* Defined in dvi2xx.c. */
  29. extern long NoSignExtend ();
  30. #define TFM_GET_TWO()  NoSignExtend (tfm_fp, 2)
  31. #define TFM_GET_FOUR() NoSignExtend (tfm_fp, 4)
  32. extern bool G_quiet;
  33. extern void Warning();
  34.  
  35. /* Defined in xmalloc.c. */
  36. /* extern void *xmalloc ();*/
  37.  
  38.  
  39. /* Read N words (N * 4 bytes) from TFM_FP and return it in *OUTBUF, unless
  40.    OUTBUF==NULL, in which case throw them away. */
  41.  
  42. static void
  43. tfm_get_n (FILEPTR tfm_fp, unsigned nwords, unsigned char **outbuf)
  44. {
  45.   unsigned n = nwords * 4;
  46.   void *buf = (void *) malloc (n);
  47.  
  48.   if (buf == NULL) {BCLOSE(tfm_fp); Fatal("(tfm): out of memory error!\n");}
  49.   read_multi (buf, 1, n, tfm_fp);
  50.   if (FEOF(tfm_fp)) {
  51.     BCLOSE(tfm_fp); Fatal("dvilj(tfm): Could not read %u bytes from TFM file.\n", n);
  52.   }
  53.  
  54.   /* If OUTBUF is null, free what we just read, else return it. */
  55.   if (outbuf) {
  56.     *outbuf = buf;
  57.   } else {
  58.     free (buf);
  59.   }
  60. }
  61.  
  62.  
  63. /* Read a string in BCPL format from DATA into STR, and terminate with a
  64.    null byte. First byte of DATA says how many characters follow.
  65.    Assume STR is long enough.  */
  66.  
  67. static void
  68. get_bcpl (unsigned char *data, unsigned char *str)
  69. {
  70.   unsigned length;
  71.  
  72.   for (length = *(data ++); length; length --) {
  73.     *(str ++) = *(data ++);
  74.   }
  75.  *str = 0;
  76. }
  77.  
  78. /* Header word 18:
  79.      2 bytes: "KN" for Karl and Norm---this identifies our extensions
  80.      1 byte : 1 if proportional, 0 otherwise
  81.      1 byte : reserved (to extend the style, if necessary)
  82.    Header word 19:
  83.      2 bytes: PCL style selection number
  84.      1 byte : reserved (to extend weight, if necessary)
  85.      1 byte : weight (signed, 2's complement, valid -7 to +7)
  86.    Header word 20:
  87.      2 bytes: reserved (to extend typeface id, if necessary)
  88.      2 bytes: PCL typeface selection number
  89.  
  90.    The first (BigEndian) byte of header word #18 is DATA[0].
  91.    Assume DATA is long enough for everything we might try to read. */
  92.  
  93. static bool
  94. get_pcl_info (unsigned char *data, unsigned *spacing, unsigned *style, int *weight, unsigned *typeface_id)
  95. {
  96.   /* No magic number for our extensions => forget it. */
  97.   if (data[0] != 'K' && data[1] != 'N')
  98.     return _FALSE;
  99.  
  100.   *spacing = data[(0* 4) + 2]; /* Third byte of first word. */
  101.  
  102.   /* First two bytes of second word. */
  103.   *style = (data[(1 * 4)] << 8) + data[(1 * 4) + 1];
  104.  
  105.   /* Last byte of second word, signed two-complement. */
  106.   *weight = data[(1 * 4) + 3];
  107.   if (*weight >= 128) *weight -= 256;
  108.  
  109.   /* Effectively all four bytes of third word. */
  110.   *typeface_id = (data[(2 * 4) + 0] << 24) + (data[(2 * 4) + 1] << 16)
  111.                + (data[(2 * 4) + 2] << 8)  + (data[(2 * 4) + 3]);
  112.  
  113.   return _TRUE;
  114. }
  115.  
  116. /* If the TFM file NAME exists, set the elements of RET and return true.
  117.    Otherwise, return false.  */
  118.  
  119. bool
  120. tfm_read_info (char *name, tfm_info_type *ret)
  121. {
  122.   /* Don't use a structure for this, since then it might occupy more
  123.      than the exactly four bytes that we need. */
  124.   unsigned char *char_info;
  125.   FILEPTR tfm_fp;
  126.   unsigned char *header_data;
  127.   unsigned char *width_raw; /* array of 1-byte data */
  128.   unsigned long4 *width_table; /* array of 4-byte fixes */
  129.   unsigned i;
  130.   unsigned lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np;
  131. #ifdef KPATHSEA
  132.   char *full_name = kpse_find_tfm (name);
  133.  
  134.   if (full_name == NULL) {
  135.     return _FALSE;
  136.   }
  137.   tfm_fp = xfopen (full_name, FOPEN_RBIN_MODE);
  138. #else /* not KPATHSEA */
  139.   char full_name[STRSIZE];
  140.   if (findfile(TFMpath, name, NULL, full_name, _TRUE, 0)) {
  141.  
  142.     /* fprintf(ERR_STREAM,"full_name=<%s>\n", full_name);*/
  143.     tfm_fp = BINOPEN(full_name);
  144.     if (tfm_fp == FPNULL) {
  145.       /* this can happen, if the calculation for max number of open
  146.        * files has to be corrected
  147.        */
  148.       fprintf(ERR_STREAM,"Error: file <%s> could not be opened\n", full_name);
  149.       return _FALSE;
  150.     }
  151.   } else {
  152.     Warning("tfm file %s.tfm not found on path <%s>\n", name, TFMpath);
  153.     return _FALSE;
  154.   }
  155. #endif /* not KPATHSEA */
  156.  
  157.   (void) TFM_GET_TWO ();   /* word length of file */
  158.   lh = TFM_GET_TWO ();     /* words of header data */
  159.   bc = TFM_GET_TWO ();     /* smallest character code */
  160.   ec = TFM_GET_TWO ();     /* largest character code */
  161.   nw = TFM_GET_TWO ();     /* words in width table */
  162.   nh = TFM_GET_TWO ();     /* words in height table */
  163.   nd = TFM_GET_TWO ();     /* words in depth table */
  164.   ni = TFM_GET_TWO ();     /* words in italic correction table */
  165.   nl = TFM_GET_TWO ();     /* words in lig/kern table */
  166.   nk = TFM_GET_TWO ();     /* words in kern table */
  167.   ne = TFM_GET_TWO ();     /* words in extensible char table */
  168.   np = TFM_GET_TWO ();     /* words of font parameter data */
  169.  
  170.   tfm_get_n (tfm_fp, lh, &header_data);
  171.   /* Only two headerbyte words are required by the TFM format, so don't
  172.      insist on all this extra stuff. */
  173.   if (lh > 2) {
  174.     get_bcpl (header_data + (2 * 4), ret->coding_scheme);
  175.   } else {
  176.     ret->coding_scheme[0] = 0;
  177.   }
  178.  
  179.   if (lh > 12) {
  180.     get_bcpl (header_data + (12 * 4), ret->family);
  181.   } else {
  182.     ret->family[0] = 0;
  183.   }
  184.  
  185.   /* Sorry for the convoluted logic. The idea is that if the family
  186.      is HPAUTOTFM, we better have our extensions -- so if we don't
  187.      have enough header words, or if we don't find what we need in
  188.      the header words, something's seriously wrong, and we shouldn't
  189.      claim to have succeeded at reading a good TFM file.  */
  190.   if (strcmp (ret->family, "HPAUTOTFM") == 0
  191.       && (lh < 20
  192.           || !get_pcl_info (&(header_data[18 * 4]),
  193.                             &ret->spacing, &ret->style, &ret->weight,
  194.                             &ret->typeface_id))) {
  195.     BCLOSE (tfm_fp);
  196.     return _FALSE;
  197.   }
  198.  
  199.   /* Initialize our returned array of widths to zero, since the TFM file
  200.      need not contain info for all character codes. */
  201.   for (i = 0; i < bc; i++) {
  202.     ret->widths[i] = 0;
  203.   }
  204.   for (i = ec + 1; i < 256; i++) {
  205.     ret->widths[i] = 0;
  206.   }
  207.  
  208.   /* The char_info is one word (four bytes) for each character in the font. */
  209.   tfm_get_n (tfm_fp, ec - bc + 1, &char_info);
  210.  
  211.   /* The width table is just nw words. */
  212.   tfm_get_n (tfm_fp, nw, &width_raw);
  213.   width_table = (unsigned long4 *) malloc (nw * 4);
  214.   if (width_table == NULL) {BCLOSE(tfm_fp); Fatal("dvilj(tfm): out of memory!\n");}
  215.  
  216.   /* But the width table contains four-byte numbers, so have to convert
  217.      from BigEndian to host order. */
  218.   for (i = 0; i < nw; i++) {
  219.     unsigned byte_offset = i * 4;
  220.     unsigned b1 = width_raw[byte_offset];
  221.     unsigned b2 = width_raw[byte_offset + 1];
  222.     unsigned b3 = width_raw[byte_offset + 2];
  223.     unsigned b4 = width_raw[byte_offset + 3];
  224.     width_table[i] = (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
  225.   }
  226.  
  227.   /* For each character, retrieve and store the TFM width. */
  228.   for (i = bc; i <= ec; i++) {
  229.     unsigned char w_i = char_info[(i - bc) * 4];
  230.     ret->widths[i] = width_table[w_i];
  231.   }
  232.  
  233.   /* Throw away everything up to the second font parameter. (Could just
  234.      seek, but I don't want to pull in the include files, etc.) */
  235.   if (np >= 2) {
  236.     tfm_get_n (tfm_fp, nh + nd + ni + nl + nk + ne + 1, NULL);
  237.     ret->interword = TFM_GET_FOUR ();
  238.   } else {
  239.     ret->interword = 0;
  240.   }
  241.  
  242.   free (header_data);
  243.   free (char_info);
  244.   free (width_raw);
  245.   free (width_table);
  246.  
  247.   BCLOSE (tfm_fp);
  248.   return _TRUE;
  249. }
  250.